package de.zainodis.triplog.data;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import de.zainodis.triplog.data.persistence.ILocationDao;
import de.zainodis.triplog.data.persistence.ITripDao;
import de.zainodis.triplog.data.share.TriplogContract;
import de.zainodis.triplog.util.DateTimeUtils;
import de.zainodis.triplog.util.Utilities;

/**
 * Represents a trip including a start and end date.
 * Created by fzarrai on 9/7/2014.
 */
@DatabaseTable(tableName = ITripDao.TABLE_NAME, daoClass = ITripDao.TripDao.class)
public class TripEntry implements Parcelable, ICrudOperations {
    private static final String TAG = "Trip";

    public static final String STRING_DEFAULT_VALUE = "null";

    @DatabaseField(generatedId = true, columnName = ITripDao.COLUMN_ID)
    private long id;
    @DatabaseField(columnName = ITripDao.COLUMN_DATE_START)
    private String start;
    @DatabaseField(columnName = ITripDao.COLUMN_DATE_END, defaultValue = STRING_DEFAULT_VALUE)
    private String end;
    //Only kept in memory for convenience purposes & passed on via parcelable
    private LocationEntry location;
    private List<DiaryEntry> diaryEntries;

    public TripEntry() {
    }

    public TripEntry(ContentValues values) {
        id = Utilities.getAsLong(values, ITripDao.COLUMN_ID);
        end = Utilities.getAsString(values, ITripDao.COLUMN_DATE_END);
        start = Utilities.getAsString(values, ITripDao.COLUMN_DATE_START);

    }

    /**
     * @return ContentValues for this instance.
     */
    public ContentValues getContentValues() {
        ContentValues values = new ContentValues();
        values.put(ITripDao.COLUMN_DATE_END, end);
        values.put(ITripDao.COLUMN_DATE_START, start);
        values.put(ITripDao.COLUMN_ID, id);
        return values;
    }

    public static final Parcelable.Creator<TripEntry> CREATOR = new Parcelable.Creator<TripEntry>() {
        public TripEntry createFromParcel(Parcel in) {
            return new TripEntry(in);
        }

        public TripEntry[] newArray(int size) {
            return new TripEntry[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeLong(id);
        out.writeString(start);
        out.writeString(end);
        out.writeParcelable(location, flags);
    }

    private TripEntry(Parcel in) {
        id = in.readLong();
        start = in.readString();
        end = in.readString();
        location = in.readParcelable(LocationEntry.class.getClassLoader());
    }


    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getStart() {
        return start;
    }

    public void setStart(String start) {
        this.start = start;
    }

    public String getEnd() {
        return end;
    }

    public void setEnd(String end) {
        this.end = end;
    }

    public boolean hasEndDate() {
        return end != null && !end.isEmpty() && !STRING_DEFAULT_VALUE.equals(end);
    }

    public LocationEntry getLocation() {
        return location;
    }

    public void setLocation(LocationEntry location) {
        this.location = location;
    }

    public void setDiaryEntries(List<DiaryEntry> diaryEntries) {
        this.diaryEntries = diaryEntries;
    }

    public List<DiaryEntry> getDiaryEntries() {
        return diaryEntries != null ? diaryEntries : new ArrayList<DiaryEntry>();
    }


    @Override
    public int delete(Context context) {
        int count = 0;
        if (id > 0) {
            //Delete the trip from the database, the content provider will take care of deleting related data
            count = context.getContentResolver().delete(TriplogContract.buildLocationUri(id), ILocationDao.COLUMN_ID + " = ?",
                    new String[]{String.valueOf(id)});
        }
        return count;
    }

    @Override
    public long createOrUpdate(Context context) {
        if (context == null) {
            Log.e(TAG, "Provided context is null.");
            return -1;
        }
        Cursor cursor = null;
        if (id > 0) {
            cursor = context.getContentResolver().query(
                    TriplogContract.buildTripUri(id), new String[]{ITripDao.COLUMN_ID}, null, null, null);
        } else {
            //If this trip has no database id, it's safe to assume that there is no trip in the database matching this one
            Log.i(TAG, "Trip has no database id, assuming newly created trip.");
        }

        if (cursor != null && cursor.moveToFirst()) {
            //We found an existing trip, store the database id
            id = cursor.getLong(cursor.getColumnIndex(ITripDao.COLUMN_ID));
        } else {
            //This is a new trip - Insert
            Uri tripInsertUri = context.getContentResolver().insert(TriplogContract.CONTENT_URI_TRIP, getContentValues());

            //Return id of the inserted trip instance
            id = ContentUris.parseId(tripInsertUri);
        }

        if (id > 0)

        {
            if (location != null) {
                //Also update location if available
                location.setFkTrip(id);
                location.createOrUpdate(context);
            }
            //Do the same for diary entries if available
            for (DiaryEntry diary : getDiaryEntries()) {
                diary.setFkTripEntry(id);
                diary.createOrUpdate(context);
            }
        }

        return id;
    }

    public static int closeOngoingTrips(Context context) {
        String where = ITripDao.COLUMN_DATE_END + " = ?";
        String[] args = new String[]{STRING_DEFAULT_VALUE};
        ContentValues values = new ContentValues();
        values.put(ITripDao.COLUMN_DATE_END, DateTimeUtils.toDbDateString(new Date()));
        return context.getContentResolver().update(TriplogContract.CONTENT_URI_TRIP, values, where, args);
    }

    /**
     * @param tripOnly true if only the trip should be retrieved; false if all related data should be retrieved.
     * @return instance of the currently ongoing trip; null if there is no ongoing trip.
     */
    public static TripEntry queryForOpen(Context context, boolean tripOnly) {
        Cursor cursor = context.getContentResolver().query(
                TriplogContract.CONTENT_URI_TRIP, null, ITripDao.COLUMN_DATE_END + " = ?",
                new String[]{STRING_DEFAULT_VALUE},
                null);
        if (cursor.moveToFirst()) {
            TripEntry entry = new TripEntry();
            entry.setId(cursor.getLong(cursor.getColumnIndex(ITripDao.COLUMN_ID)));
            entry.setStart(cursor.getString(cursor.getColumnIndex(ITripDao.COLUMN_DATE_START)));
            entry.setEnd(cursor.getString(cursor.getColumnIndex(ITripDao.COLUMN_DATE_END)));

            if (tripOnly) {
                return entry;
            }

            //Try to find the location too
            entry.setLocation(LocationEntry.getByTripId(context, entry.getId()));

            //... and related diary entries
            entry.setDiaryEntries(DiaryEntry.getByTripId(context, entry.getId()));

            return entry;
        }
        return null;
    }

}
